package deployer

import (
	"context"
	"fmt"
	"path/filepath"
	"time"

	"xindl/deployer/internal/builder"
	"xindl/deployer/internal/docker"
	"xindl/deployer/internal/git"
	"xindl/deployer/pkg/errors"
	"xindl/deployer/pkg/logger"
)

// 部署配置
type DeployConfig struct {
	// 服务信息
	ServiceName string
	Port        int
	Env         string
	Replicas    int

	// 代码信息
	Repository string
	Branch     string

	// 构建配置
	BuildTool  string
	JDKVersion string
	SkipTests  bool

	// Docker配置
	DockerMirror string

	// 资源限制
	CPULimit      string
	CPURequest    string
	MemoryLimit   string
	MemoryRequest string

	// 健康检查
	HealthCheck    bool
	HealthEndpoint string

	// 调试模式
	Debug bool
}

// 部署协调器
type Coordinator struct {
	config  *DeployConfig
	log     *logger.Logger
	workDir string
}

// 创建部署协调器
func NewCoordinator(config *DeployConfig) *Coordinator {
	return &Coordinator{
		config:  config,
		log:     logger.New(config.Debug).WithPrefix("部署协调器"),
		workDir: filepath.Join(".deployer", "workspace", config.ServiceName),
	}
}

// 执行部署
func (c *Coordinator) Deploy(ctx context.Context) error {
	startTime := time.Now()

	// 1. 克隆代码
	gitClient := git.NewClient(c.config.ServiceName, c.config.Debug)
	if err := gitClient.Clone(ctx, c.config.Repository, c.config.Branch); err != nil {
		return errors.WithContext(err, "service", c.config.ServiceName)
	}
	defer gitClient.Clean()

	// 2. 构建服务
	buildResult, err := c.buildService(ctx, gitClient.WorkDir())
	if err != nil {
		return errors.WithContext(err, "service", c.config.ServiceName)
	}

	// 3. 部署服务
	if err := c.deployService(ctx, buildResult.ImageID); err != nil {
		return errors.WithContext(err, "service", c.config.ServiceName)
	}

	c.log.Info("部署完成，耗时: %.2f秒", time.Since(startTime).Seconds())
	return nil
}

// 构建服务
func (c *Coordinator) buildService(ctx context.Context, workDir string) (*builder.BuildResult, error) {
	startTime := time.Now()

	// 创建构建配置
	buildConfig := builder.NewBuildConfigBuilder(c.config.ServiceName, c.config.BuildTool).
		WithWorkDir(workDir).
		WithCacheDir(filepath.Join(".deployer", "cache", c.config.ServiceName)).
		WithJDKVersion(c.config.JDKVersion).
		WithSkipTests(c.config.SkipTests).
		WithDockerConfig(
			c.config.DockerMirror,
			c.config.ServiceName,
			c.config.Env,
		).
		WithResourceLimits(
			c.config.CPULimit,
			c.config.MemoryLimit,
		)

	// 创建构建器
	builderFactory := builder.NewBuilderFactory(c.config.Debug)
	b, err := builderFactory.CreateBuilder(c.config.BuildTool)
	if err != nil {
		return nil, errors.WithContext(err, "service", c.config.ServiceName)
	}

	// 准备构建环境
	config, err := buildConfig.Build()
	if err != nil {
		return nil, errors.WithContext(err, "service", c.config.ServiceName)
	}

	if err := b.Prepare(ctx, config); err != nil {
		return nil, errors.WithContext(err, "service", c.config.ServiceName)
	}

	// 执行构建
	result, err := b.Build(ctx)
	if err != nil {
		return nil, errors.WithContext(err, "service", c.config.ServiceName)
	}

	c.log.Info("构建完成，耗时: %.2f秒", time.Since(startTime).Seconds())
	return result, nil
}

// 部署服务
func (c *Coordinator) deployService(ctx context.Context, imageID string) error {
	startTime := time.Now()

	// 创建服务管理器
	manager, err := docker.NewServiceManager(c.config.Debug)
	if err != nil {
		return errors.WithContext(err, "service", c.config.ServiceName)
	}

	// 创建服务配置
	serviceConfig := &docker.ServiceConfig{
		Name:     c.config.ServiceName,
		Image:    imageID,
		Replicas: uint64(c.config.Replicas),
		Port:     uint32(c.config.Port),
		
		CPULimit:      c.config.CPULimit,
		CPURequest:    c.config.CPURequest,
		MemoryLimit:   c.config.MemoryLimit,
		MemoryRequest: c.config.MemoryRequest,
		
		Env: map[string]string{
			"ENV":     c.config.Env,
			"PORT":    fmt.Sprintf("%d", c.config.Port),
			"VERSION": c.config.Branch,
		},
		
		HealthCheck:   c.config.HealthCheck,
		HealthPath:    c.config.HealthEndpoint,
	}

	// 部署服务
	if err := manager.Deploy(ctx, serviceConfig); err != nil {
		// 尝试回滚
		rollbackErr := manager.Rollback(ctx, c.config.ServiceName)
		if rollbackErr != nil {
			c.log.Error("服务回滚失败: %v", rollbackErr)
		}
		return errors.WithContext(err, "service", c.config.ServiceName)
	}

	c.log.Info("部署完成，耗时: %.2f秒", time.Since(startTime).Seconds())

	// 启动服务监控
	statusChan, err := manager.Watch(ctx, c.config.ServiceName)
	if err != nil {
		return errors.WithContext(err, "service", c.config.ServiceName)
	}

	// 输出服务状态
	go func() {
		for status := range statusChan {
			c.log.Info("服务状态: 运行中=%d/%d, 失败=%d, 更新状态=%s",
				status.RunningTasks, status.DesiredTasks,
				status.FailedTasks, status.UpdateStatus)
		}
	}()

	return nil
}
